Function.RegisterNamespace("System.Web");

System.Web.Dom=new function(){
    // Public Members
    this.BaseHref;
    this.VersionInfo;
        
    // ctor
    function Dom(){
        this.BaseHref="/";
        if(typeof(navigator)!="undefined")this.VersionInfo=navigator.userAgent;
        else if(typeof(WScript)!="undefined")this.VersionInfo=String.Format("{0} Version {1} Build {2}",WScript.Name,WScript.Version,WScript.BuildVersion);
        // TODO: other environments?    
    }
    Dom.apply(this,arguments);

    // Public Methods    
    this.AppendContent=function(node,content){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.AppendContent: 'node' must be a valid Node.");
        if(content==undefined)throw new Error("System.Web.Dom.AppendContent: 'content' must be convertible to String.");
        node.innerHTML+=content;
    };

    this.AppendText=function(node,text){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.AppendText: 'node' must be a valid Node.");
        if(text==undefined)throw new Error("System.Web.Dom.AppendText: 'text' must be convertible to String.");
        node.appendChild(node.ownerDocument.createTextNode(text));
    };
    
    this.ClearContent=function(node){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.ClearContent: 'node' must be a valid Node.");
        node.innerHTML='';
    };

    this.CreateElement=function(parentNode,properties,tagName,ownerDocument){
        if(arguments.length>3){
            if(ownerDocument==undefined)throw new Error("System.Web.Dom.CreateElement: 'ownerDocument' must be a valid Object.");
            if(!ownerDocument.createElement)throw new Error("System.Web.Dom.CreateElement: 'ownerDocument' does not implement method 'createElement(tagName)'.");
        }
        var node=(ownerDocument||document).createElement(tagName||"div");
        Object.Set(node,properties);
        if(parentNode!=undefined){
            if(!parentNode.appendChild)throw new Error("System.Web.Dom.CreateElement: 'parentNode' does not implement method 'appendChild(node)'.");
            parentNode.appendChild(node);
        }
        return node;
    };
    
    this.Decode=function(markup,container){
        if(container==undefined)container=this.CreateElement();
        this.SetContent(container,markup);
        return this.GetText(container);
    };
    
    this.Encode=function(text,container){
        if(container==undefined)container=this.CreateElement();
        this.SetText(container,text);
        return this.GetContent(container);
    };
    
    this.Focus=function(node,select){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.Focus: 'node' must be a valid Node.");
        try{
            if(select&&node.select)node.select();
            else node.focus();
            return true;
        }catch(e){
            return false;
        }
    };

    this.GetAttribute=function(node,name){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.GetAttribute: 'node' must be a valid Node.");
        if(node.attributes)return node.attributes[name]&&node.attributes[name].nodeValue;
        if(node.getAttribute)return node.getAttribute(name);
        return node[name];
    };

    this.GetContent=function(node){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.GetContent: 'node' must be a valid Node.");
        return node.innerHTML;
    };

    this.GetElement=function(id,ownerDocument){
        if(ownerDocument!=undefined&&!Object.IsType(Function,ownerDocument.getElementById))throw new Error("System.Web.Dom.GetElement: 'ownerDocument' does not implement method 'getElementById()'.");
        return (ownerDocument||document).getElementById(id);
    };

    this.GetOffset=function(node,parentLimit,stopOnOverflow){
        var offset={x:0,y:0};
        while(node){
            if(node==parentLimit||node==document||node.nodeType==11)break;
            if(stopOnOverflow){
                if(System.Web.Style.GetStyle(node,"position")!="static")break;
                if(System.Web.Style.GetStyle(node,"overflow")!="visible")break;
            }
            offset.x+=node.offsetLeft;
            offset.y+=node.offsetTop;
            node=node.offsetParent||node.parentNode;
        }
        return offset;
    };

    this.GetText=function(node){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.GetText: 'node' must be a valid Node.");
        return node.textContent||node.innerText;
    };
    
    this.Remove=function(node){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.Remove: 'node' must be a valid Node.");
        if(node.parentNode&&node.parentNode.removeChild)node.parentNode.removeChild(node);
    };

    this.RemoveAttribute=function(node,name,nameSpace){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.RemoveAttribute: 'node' must be a valid Node.");
        throw new Error("NotImplementedException");
    };

    this.ResolveUrl=function(url){
        if(!(url&&url.toString))throw new Error("System.Web.Dom.ResolveUrl: 'url' must be convertible to String.");
        return url.toString().replace(/^~\//,this.BaseHref);
    };

    this.SelectNodes=function(base,matches,limit){
        if(matches==undefined)throw new Error("System.Web.Dom.SelectNodes: 'matches' must be a valid Object.");
        if(arguments>2&&limit!=undefined){
            if(isNaN(limit))throw new Error("System.Web.Dom.SelectNodes: 'limit' must be a valid Number.");
            limit=parseInt(limit);
        }
        return selectNodes(base||document.documentElement,matches,limit);
    };
    
    this.SelectSingleNode=function(base,matches){
        if(matches==undefined)throw new Error("System.Web.Dom.SelectSingleNode: 'matches' must be a valid Object.");
        return selectNodes(base||document.documentElement,matches,1)[0]||null;
    };

    this.SetAttribute=function(node,name,value,nameSpace){
        if(node==undefined||!node.nodeType)throw new Error("System.Web.Dom.SetAttribute: 'node' must be a valid Node.");
        if(!Object.IsType(Function,node.setAttribute))throw new Error("System.Web.Dom.SetAttribute: 'node' does not implement the method 'setAttribute()'.");
        if(nameSpace){
            if(Object.IsType(Function,node.setAttributeNS))node.setAttributeNS(nameSpace,name,value);
            else node.setAttribute(String.Format("{0}:{1}",nameSpace,name),value);
        }else{
            node.setAttribute(name,value);
        }
    };

    this.SetContent=function(node,content){
        this.ClearContent(node);
        this.AppendContent(node,content);
    };
    
    this.SetText=function(node,text){
        this.ClearContent(node);
        this.AppendText(node,text);
    };
        
    // Private Methods
    function selectNodes(element,matches,limit){
        var output=[];
        if(element&&element.hasChildNodes){
            var nodes=element.childNodes;
            for(var i=0;i<nodes.length;i++){
                if(Object.Contains(matches,nodes[i]))output.push(nodes[i]);
                else output=output.concat(selectNodes(nodes[i],matches,limit-output.length));
                if(output.length==limit)break;
            }
        }
        return output;
    }
};
